/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2019-2022. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * Description:
 * Author: huawei
 * Create: 2019-10-15
 */

#ifndef DEVMM_COMMON_H
#define DEVMM_COMMON_H
#include <linux/fs.h>
#include <linux/uaccess.h>

#include "devmm_proc_info.h"
#include "svm_proc_gfp.h"

#ifndef __GFP_ACCOUNT

#ifdef __GFP_KMEMCG
#define __GFP_ACCOUNT __GFP_KMEMCG /* for linux version 3.10 */
#endif

#ifdef __GFP_NOACCOUNT
#define __GFP_ACCOUNT 0 /* for linux version 4.1 */
#endif

#endif

#define DEVMM_BITS_PER_CHAR 8
#define DEVMM_PAGENUM_PER_HPAGE (HPAGE_SIZE / PAGE_SIZE)

#define DEVMM_WAKEUP_TIMEINTERVAL 500 /* 0.5s */

#define DEVMM_SVM_MMU_MIN_SLEEP 50
#define DEVMM_SVM_MMU_MAX_SLEEP 60

#define SVM_DEV_INST_MAX_NUM (SVM_MAX_AGENT_NUM * DEVMM_MAX_VF_NUM)

struct svm_id_inst {
    u32 devid;
    u32 vfid;
};

static inline void svm_id_inst_pack(struct svm_id_inst *inst, u32 devid, u32 vfid)
{
    inst->devid = devid;
    inst->vfid = vfid;
}

static inline u32 svm_id_inst_to_dev_inst(struct svm_id_inst *id_inst)
{
    return (id_inst->devid * DEVMM_MAX_VF_NUM + id_inst->vfid);
}

static inline bool devmm_heap_subtype_is_matched(u32 heap_subtype, u32 mask)
{
    return ((mask & (1ul << heap_subtype)) != 0) ? true : false;
}

static inline bool devmm_pages_is_continue(struct page *pre_page, struct page *post_page)
{
    return (page_to_pfn(pre_page) + 1) == page_to_pfn(post_page);
}

static inline void devmm_isb(void)
{
#if defined(__arm__) || defined(__aarch64__)
    isb();
#endif
}

extern bool g_devmm_true;
extern bool g_devmm_false;

u32 devmm_get_max_page_num_of_per_msg(u32 *bitmap);
void devmm_try_usleep_by_time(u32 *pre_stamp, u32 time);
void devmm_try_cond_resched(u32 *pre_stamp);
void devmm_try_cond_resched_by_time(u32 *pre_stamp, u32 time);
bool devmm_smmu_is_opening(void);
int devmm_get_user_pages_fast(u64 va, u64 total_num, int write, struct page **pages);
void devmm_unpin_user_pages(struct page **pages, u64 page_num, u64 unpin_num);
void devmm_pin_user_pages(struct page **pages, u64 page_num);
u64 devmm_get_pagecount_by_size(u64 vptr, u64 sizes, u32 page_size);
int devmm_check_va_add_size_by_heap(struct devmm_svm_heap *heap, u64 va, u64 size);
bool devmm_check_input_heap_info(struct devmm_svm_process *svm_pro,
    struct devmm_update_heap_para *cmd, u32 devid);
bool devmm_check_common_input_heap_info(struct devmm_svm_process *svm_pro,
    struct devmm_update_heap_para *cmd, u32 devid);
ssize_t devmm_read_file(struct file *fp, char *dst_addr, size_t fsize, loff_t *pos);
char *devmm_read_line(struct file *fp, char *buf, u32 buf_len);
void *devmm_kvalloc(u64 size, gfp_t flags);
void *devmm_kvzalloc(u64 size);
void devmm_kvfree(const void *ptr);
void devmm_set_heap_used_status(struct devmm_svm_heap *heap, u64 va, u64 size);
struct vm_area_struct *devmm_find_vma(struct devmm_svm_process *svm_proc, u64 vaddr);
struct vm_area_struct *devmm_find_vma_custom(struct devmm_svm_process *svm_proc, u32 idx, u64 vaddr);
int devmm_update_heap_info(struct devmm_svm_process *svm_process, struct devmm_update_heap_para *cmd);
void devmm_free_heap_struct(struct devmm_svm_process *svm_process, u32 heap_idx, u32 heap_num);
bool devmm_check_heap_is_entity(struct devmm_svm_heap *heap);
int devmm_shm_inform_host_get_pages(struct devmm_svm_process_id *process_id, u64 va, u64 size);
int devmm_shm_inform_host_put_pages(struct devmm_svm_process_id *process_id, u64 va, u64 size);
void devmm_dev_fault_flag_set(u32 *flag, u32 shift, u32 wide, u32 value);
u32 devmm_dev_fault_flag_get(u32 flag, u32 shift, u32 wide);
bool devmm_is_pcie_connect(u32 dev_id);
bool devmm_is_host_agent(u32 agent_id);
const char *devmm_get_chrdev_name(void);
void devmm_set_proc_vma(struct mm_struct *mm, struct vm_area_struct *vma[], u32 vma_num);
int devmm_get_svm_pages(struct vm_area_struct *vma, u64 va, u64 num, struct page **pages);

void devmm_svm_mem_enable(struct devmm_svm_process *svm_proc);
void devmm_svm_mem_disable(struct devmm_svm_process *svm_proc);
bool devmm_svm_mem_is_enable(struct devmm_svm_process *svm_proc);

void devmm_phy_addr_attr_pack(struct devmm_svm_process *svm_proc, u32 pg_type, u32 mem_type, bool is_continuous,
    struct devmm_phy_addr_attr *attr);
u64 devmm_get_tgid_start_time(void);

#ifdef EMU_ST
struct vm_area_struct *devmm_find_vma_from_mm(struct mm_struct *mm, u64 vaddr);
#endif
#endif /* __DEVMM_COMMON_H__ */
